package com.tilaiedu.mvc.config;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import com.tilaiedu.mvc.interceptor.PermissionInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.format.FormatterRegistry;
import org.springframework.format.datetime.DateFormatter;
import org.springframework.format.datetime.standard.DateTimeFormatterRegistrar;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.multipart.MultipartResolver;
import org.springframework.web.multipart.support.StandardServletMultipartResolver;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.TimeZone;

/**
 * @Author xlzhang
 * @Date 2022/5/25 9:33
 * @Version 1.0
 * @Description TODO
 */
@Configuration
@ComponentScan({"com.tilaiedu.mvc.controller","com.tilaiedu.mvc.handler"})
// 开启springmvc的注解驱动，默认加载web应用的相关组件，比如消息转换器
@EnableWebMvc
public class SpringMvcConfig implements WebMvcConfigurer {

    private static final String TIME_ZONE = "GMT+8";
    private static final String DEFAULT_DATETIME_PATTERN = "yyyy-MM-dd HH:mm:ss";
    private static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
    private static final String DEFAULT_TIME_FORMAT = "HH:mm:ss";

    // 这个接口会先执行系统默认的消息转换，再执行这里配置的自定义转换器
    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        for (HttpMessageConverter<?> converter : converters) {
            if (converter instanceof MappingJackson2HttpMessageConverter){
                // 初始化一个jackson的转换对象
                ObjectMapper objectMapper = new ObjectMapper();
                // 指定时区
                objectMapper.setTimeZone(TimeZone.getTimeZone(TIME_ZONE));
                // 日期类型字符串处理
                // 这里设置的是date类型的处理格式
                objectMapper.setDateFormat(new SimpleDateFormat(DEFAULT_DATETIME_PATTERN));
                // 设置参数为null时不序列化
                objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);

                // Java8日期日期处理
                JavaTimeModule javaTimeModule = new JavaTimeModule();
                javaTimeModule.addSerializer(LocalDateTime.class,
                        new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATETIME_PATTERN)));
                javaTimeModule.addSerializer(LocalDate.class,
                        new LocalDateSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)));
                javaTimeModule.addSerializer(LocalTime.class,
                        new LocalTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)));

                javaTimeModule.addDeserializer(LocalDateTime.class,
                        new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATETIME_PATTERN)));
                javaTimeModule.addDeserializer(LocalDate.class,
                        new LocalDateDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)));
                javaTimeModule.addDeserializer(LocalTime.class,
                        new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)));

                objectMapper.registerModule(javaTimeModule);
                // 将配置好的objectMapper添加到消息转换器对象中
                ((MappingJackson2HttpMessageConverter) converter).setObjectMapper(objectMapper);
            }
        }
    }

    // ajax + 浏览器才会触发跨域问题
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        // 所有请求都检查当前的跨域配置
        registry.addMapping("/**")
                // 配置跨域的来源
                .allowedOrigins("http://127.0.0.1:5500/", "null")
                // 当前支持的请求方式
                .allowedMethods("POST", "GET", "PUT", "OPTIONS", "DELETE")
                // 预计请求的时长 秒
                .maxAge(3600)
                // 是否支持cookie， true代表支持cookie
                .allowCredentials(true);
    }

    // 配置文件上传
    // 文件上传的解析器必须固定注入容器的id名称为 multipartResolver
    @Bean("multipartResolver")
    public MultipartResolver multipartResolver(){
        /**
         * StandardServletMultipartResolver是基于servlet3.1原生上传组件封装的
         * 上传参数需要在web.xml或WebInit中配置
         */
        return new StandardServletMultipartResolver();
    }

    @Override
    public void addFormatters(FormatterRegistry registry) {
        // 只能处理date类型
        DateFormatter formatter = new DateFormatter();
        formatter.setFallbackPatterns("yyyy-MM-dd","yyyy-MM-dd HH:mm:ss");
        registry.addFormatter(formatter);
        // 配置JDK8的新日期API
        final DateTimeFormatterRegistrar formatterRegistrar =
                new DateTimeFormatterRegistrar();
        formatterRegistrar.setTimeFormatter(DateTimeFormatter.ofPattern("HH:mm:ss"));
        formatterRegistrar.setDateFormatter(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        formatterRegistrar.setDateTimeFormatter(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        formatterRegistrar.registerFormatters(registry);
    }

    /**
     * 注册拦截器
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 注册拦截器，设置拦截的资源路径
        registry.addInterceptor(new PermissionInterceptor())
                //  /** 代表拦截所有请求资源
                .addPathPatterns("/**")
                // 那些资源不需要拦截，可以设置这个排除选项
                .excludePathPatterns("/login","/captcha");
    }

}
